import datetime
import uuid
import warnings
from calendar import timegm
from datetime import datetime as dt

from django.conf import settings
from django.core.cache import cache
from rest_framework import exceptions
from rest_framework_jwt.compat import get_username, get_username_field
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.utils import jwt_decode_handler

from main.common.utils.utils import get_client_ip
from main.models import JwtLog

CAS_LOGIN_EXPIRE = getattr(settings, 'CAS_LOGIN_EXPIRE', True)
CAS_LOGIN_EXPIRE_TIME = getattr(settings, 'CAS_LOGIN_EXPIRE_TIME', 7200)


def get_user_perms(user):
    all_perms = user.get_all_permissions()
    sso_perms = [
        perm.split('.')[1]
        for perm in all_perms if perm.split('.')[0] == 'main'
    ]
    return sso_perms


def jwt_response_payload_handler(token, user=None, request=None):
    if CAS_LOGIN_EXPIRE:  # 启用登录设备唯一，登录 或者 refresh token 会导致其它设备下线
        token_before_refresh = ''
        try:
            token_before_refresh = request.data['token']  # 重复刷新token会失败
        except Exception:
            pass
        key = 'LOGIN_USER_' + str(user.id)

        if token_before_refresh:
            if cache.get(key) != token_before_refresh:
                raise exceptions.AuthenticationFailed('token 错误请重新登录')

        cache.set(key, token, CAS_LOGIN_EXPIRE_TIME)

    payload = {
        'token': token,
        'username': user.username,
        'permissions': get_user_perms(user),
        'uid': user.id,
    }
    token_payload = jwt_decode_handler(token)
    ip_addr = get_client_ip(request)
    JwtLog(user=user, ip_addr=ip_addr, exp=datetime.datetime.fromtimestamp(token_payload['exp'])).save()
    return payload


def jwt_payload_handler(user):
    username_field = get_username_field()
    username = get_username(user)

    warnings.warn(
        'The following fields will be removed in the future: '
        '`email` and `user_id`. ',
        DeprecationWarning
    )

    payload = {
        'user_id': user.pk,
        'username': username,
        'exp': dt.utcnow() + api_settings.JWT_EXPIRATION_DELTA
    }
    if hasattr(user, 'email'):
        payload['email'] = user.email
    if isinstance(user.pk, uuid.UUID):
        payload['user_id'] = str(user.pk)

    payload[username_field] = username

    # Include original issued at time for a brand new token,
    # to allow token refresh
    if api_settings.JWT_ALLOW_REFRESH:
        payload['orig_iat'] = timegm(
            dt.utcnow().utctimetuple()
        )

    if api_settings.JWT_AUDIENCE is not None:
        payload['aud'] = api_settings.JWT_AUDIENCE

    if api_settings.JWT_ISSUER is not None:
        payload['iss'] = api_settings.JWT_ISSUER
        payload['key'] = api_settings.JWT_ISSUER

    return payload
